﻿/*
 * 类    名：ExpressionProvider
 * 
 * 功能描述：表达式转化SQL语句
 * 
 * 创 建 者：CHZ
 * 
 * 创建日期：2012.8.12
 * 
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Collections;

namespace PUBCOM
{
    public class ExpressionProvider
    {

        /// <summary>
        /// 解析表达式为sql所需格式
        /// </summary>
        public static string ToSql(Expression Exp) 
        {
            if (Exp == null) return "";
            string Str = string.Empty;
            if (Exp is Expression)
            {

                switch (Exp.NodeType)
                {
                    case ExpressionType.Call:
                        MethodCallExpression mExp = (MethodCallExpression)Exp;
                        Str = Router(mExp).ToString();
                        break;
                    case ExpressionType.MemberAccess:
                        break;
                    default:
                        BinaryExpression bExp = (BinaryExpression)Exp;
                        Str = ConvertToString(bExp.Left, bExp.Right, bExp.NodeType);
                        break;
                }
                

               
            }
            return Str;
        }

        /// <summary>
        /// 转换表达式
        /// </summary>
        public static string ConvertToString(Expression ExpLeft, Expression ExpRight, ExpressionType ExpType)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("(");
            sb.Append(Router(ExpLeft));//处理左边
            sb.Append(TypeCast(ExpType));//处理符号
            string tmpStr = Router(ExpRight).ToString();//处理右边
            if (tmpStr == "null")
            {
                string strSb = sb.ToString();
                if (strSb.EndsWith(" ="))
                {
                    strSb = strSb.Substring(0, sb.Length - 2) + " is null";
                }
                else if (strSb.EndsWith("<>"))
                {
                    strSb = strSb.Substring(0, sb.Length - 2) + " is not null";
                }
                sb = new StringBuilder(strSb);
            }
            else
            {
                sb.Append(tmpStr);
            }
            return sb.Append(")").ToString();
        }

        /// <summary>
        /// 表达式路由计算
        /// </summary>
        public static object Router(Expression Exp)
        {
            if (Exp is BinaryExpression)
            {
                BinaryExpression be = ((BinaryExpression)Exp);
                return ConvertToString(be.Left, be.Right, be.NodeType);
            }
            else if (Exp is MemberExpression)
            {
                if (!Exp.ToString().StartsWith("value("))
                {
                    MemberExpression me = ((MemberExpression)Exp);
                    return me.ToString();
                }
                else
                {
                    var result = Expression.Lambda(Exp).Compile().DynamicInvoke();
                    if (result == null)
                    {
                        return "null";
                    }
                    if (result is ValueType)
                    {
                        if (result is bool)
                            return bool.Parse(result.ToString()) ? "1" : "0";
                        else
                            return string.Format("'{0}'", result.ToString()); //return result.ToString();
                    }
                    else if (result is string || result is DateTime || result is char)
                    {
                        return string.Format("'{0}'", result.ToString());
                    }
                    else if (result is string[])
                    {
                        string[] ss=result as string[];
                        for (int i = 0; i < ss.Count();i++ )
                        {
                            ss[i] = "'" + ss[i] + "'";
                        }
                        return result;
                    }
                }

            }
            else if (Exp is NewArrayExpression)
            {

                NewArrayExpression ae = ((NewArrayExpression)Exp);
                object[] array = new object[ae.Expressions.Count];
                int i = 0;
                foreach (Expression ex in ae.Expressions)
                {
                    array[i] = Router(ex);
                    i++;
                }
                return array;
            }
            else if (Exp is MethodCallExpression)
            {
                MethodCallExpression mce = (MethodCallExpression)Exp;
                if (mce.Method.Name == "Like")
                {
                    return string.Format("({0} like {1})", Router(mce.Arguments[0]), Router(mce.Arguments[1]));
                }
                else if (mce.Method.Name == "NotLike")
                {
                    return string.Format("({0} not like {1})", Router(mce.Arguments[0]), Router(mce.Arguments[1]));
                }
                else if (mce.Method.Name == "In")
                {
                    return string.Format("{0} in ({1})", Router(mce.Arguments[0]), Router(mce.Arguments[1]));
                }
                else if (mce.Method.Name == "NotIn")
                {
                    return string.Format("{0} not in ({1})", Router(mce.Arguments[0]), Router(mce.Arguments[1]));
                }
                else if (mce.Method.Name == "Contains")
                {
                    return string.Format("{0} like '%'+{1}+'%'", mce.Object, Router(mce.Arguments[0]));
                }
                else if (mce.Method.Name == "StartsWith")
                {
                    return string.Format("{0} like {1}+'%'", mce.Object, Router(mce.Arguments[0]));
                }
                else if (mce.Method.Name == "SQLLen")
                {
                    return string.Format("len({0})={1}", Router(mce.Arguments[0]), Router(mce.Arguments[1]));
                }
                else if (mce.Method.Name == "SQLCompareToLen")
                {
                    return string.Format("len({0}){2}{1}", Router(mce.Arguments[0]), Router(mce.Arguments[1]), mce.Arguments[2].ToString().Replace("\"", ""));
                }
                else if (mce.Method.Name == "SQLInArray")
                {

                    StringBuilder Rstr = new StringBuilder();
                    string str = mce.Arguments[0].ToString();
                    object[] array = (object[])Router(mce.Arguments[1]);
                    if (array != null)
                    {
                        foreach (string s in array)
                            Rstr.Append(str + "=" + s + ",");
                        str = " ( " + Rstr.ToString().Trim(',').Replace(",", " or ") + ")";
                    }
                    return str;
                }
            }
            else if (Exp is ConstantExpression)
            {
                ConstantExpression ce = ((ConstantExpression)Exp);
                if (ce.Value == null)
                {
                    return "null";
                }
                else if (ce.Value is ValueType)
                {
                    if (ce.Value is bool)
                        return bool.Parse(ce.Value.ToString()) ? "1" : "0";
                    else
                        return ce.Value.ToString();
                }
                else if (ce.Value is string || ce.Value is DateTime || ce.Value is char)
                {
                    return string.Format("'{0}'", ce.Value.ToString());
                }
            }
            else if (Exp is UnaryExpression)
            {
                UnaryExpression ue = ((UnaryExpression)Exp);
                return Router(ue.Operand);
            }
            else if (Exp is InvocationExpression)
            {
                InvocationExpression ie = ((InvocationExpression)Exp);
                return Router(((LambdaExpression)ie.Expression).Body);
            }
            
            return null;
        }

        /// <summary>
        /// 获取表达式运算符对应sql运算符
        /// </summary>
        public static string TypeCast(ExpressionType ExpType)
        {
            switch (ExpType)
            {
                case ExpressionType.And:
                case ExpressionType.AndAlso:
                    return " and ";
                case ExpressionType.Equal:
                    return " =";
                case ExpressionType.GreaterThan:
                    return " >";
                case ExpressionType.GreaterThanOrEqual:
                    return ">=";
                case ExpressionType.LessThan:
                    return "<";
                case ExpressionType.LessThanOrEqual:
                    return "<=";
                case ExpressionType.NotEqual:
                    return "<>";
                case ExpressionType.Or:
                case ExpressionType.OrElse:
                    return " or ";
                case ExpressionType.Add:
                case ExpressionType.AddChecked:
                    return "+";
                case ExpressionType.Subtract:
               case ExpressionType.SubtractChecked:
                    return "-";
                case ExpressionType.Divide:
                    return "/";
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                    return "*";
                default:
                    return null;
            }

        }

    }
}